import string


class LexicalAnalysis:
    def __init__(self, new_file, file):
        self.operator = ["+", "-", "*", "/", "<", "<=", ">", ">=", "=", "==",
                         "!=", ";", "(", ")", "^", ",", "\"", "\'", "#", "&",
                         "&&", "|", "||", "%", "~", "<<", ">>", "[", "]", "{",
                         "}", "\\", ".", "?", ":", "!", "_"]
        self.key = ["break", "case", "char", "const", "continue",
                    "default", "do", "double", "else", "enum", "extern",
                    "float", "for", "goto", "if", "int", "long",
                    "register", "return", "short", "signed", "sizeof", "static",
                    "struct", "switch", "typedef", "union", "unsigned", "void",
                    "volatile", "while"]
        self.delimiters = ['(', ')', ';']
        self.new_file = new_file
        self.file = file
        self.token = []
    
    def read(self):
        f2 = open(self.new_file, 'w+')
        data_txt = ''.join(open(self.file, 'r').readlines())
        
        for line in data_txt.split('\n'):
            line = line.strip()
            line = line.replace('\\t', '')
            line = line.replace('\\n', '')
            
            if not line:
                continue
            else:
                f2.write(line)
        f2.close()
    
    def process(self):
        operator = self.operator
        key = self.key
        delimiters = self.delimiters
        file = self.file
        
        token = []
        global flag
        flag = 1
        data = open(file, 'r').readlines()
        
        for line in data:
            flag = 1
            word = ''
            word_line = []
            i = 0
            
            while i < len(line):
                word += line[i]
                
                l = line[i]
                if (l not in operator) and (l not in key) and (l not in delimiters) and \
                        (not (l in string.ascii_letters or l in string.digits or l == '_' or l is ' ')):
                    syx = 'undefined string!'
                    word_line.append({word: syx})
                    print("index:{},string{} : error happened".format(i + 1, word))
                    i += 1
                    word = ''
                    continue
                
                if line[i] == ' ' or (line[i] in delimiters) or (line[i] in operator):
                    
                    if word[0] in string.digits:
                        for j in word[1:]:
                            if j in string.ascii_letters or j == '_':
                                syx = 'undefined string!'
                                word_line.append({word: syx})
                                flag = 0
                                print("index:{},string {} : error happend!".format(i + 1, word))
                                break
                        if flag == 0:
                            word = ''
                            continue
                    
                    if word[0].isalpha() or word[0] == '_':
                        word = word[:-1]
                        
                        for j in word[1:]:
                            flag = 1
                            if (j in string.ascii_letters or j in string.digits or j == '_') == 1:
                                continue
                            else:
                                print(word + 'has wrong string')
                                flag = 0
                                break
                        if flag:
                            if word in key:
                                syx = 'keyword'
                                word_line.append({word: syx})
                            else:
                                syx = 'ID'
                                word_line.append({word: syx})
                        else:
                            syx = 'undefined string!'
                            word_line.append({word: syx})
                    elif word[:-1].isdigit():
                        syx = 'int'
                        word_line.append({word[:-1]: syx})
                    
                    if line[i] in delimiters:
                        syx = 'split'
                        word_line.append({line[i]: syx})
                    elif line[i] in operator:
                        syx = 'op'
                        if i < len(line) - 1:
                            s = line[i] + line[i + 1]
                            if s in operator:
                                word_line.append({s: syx})
                                i += 1
                            else:
                                word_line.append({line[i]: syx})
                    word = ''
                i += 1
            token.append(word_line)
        self.token = token[0]
    
    def show(self):
        for t in range(0, len(self.token)):
            print('< ' + list(self.token[t].keys())[0] + ' , ' + list(self.token[t].items())[0][1] + ' >')
    
    def __call__(self, *args, **kwargs):
        return self.token


if __name__ == '__main__':
    # lex = LexicalAnalysis("../test_data/testPreDeal1.txt", "../test_data/example/00_arr_defn2.sy")
    # lex = LexicalAnalysis("../test_data/testPreDeal1.txt", "../test_data/example/00_main.sy")
    # lex = LexicalAnalysis("../test_data/testPreDeal1.txt", "../test_data/example/01_var_defn.sy")
    # lex = LexicalAnalysis("../test_data/testPreDeal1.txt", "../test_data/example/00_arr_defn2.sy")
    lex = LexicalAnalysis("../test_data/testPreDeal1.txt", "../test_data/example/00_err_1.sy")
    # lex = LexicalAnalysis("../test_data/testPreDeal1.txt", "../test_data/example/00_err_2.sy")
    lex.read()
    lex.process()
    lex.show()
